<?php
require_once 'Zend/Controller/Plugin/Abstract.php';

/**
 * 支付宝接口
 * 
 * Zend Framewrok 专用
 * 
 * @author 高强
 */
class Custom_Controller_Payment_Alipay extends Zend_Controller_Plugin_Abstract
{
	private $_payment;
	private $_config;
	
	private static $_out_trade_no;
	
	/**
	 * 初始化
	 * 
	 * @ignore
	 */
	public function __construct()
	{
		$this->_config = $this->_getConfig();
		
		switch ($this->_config['alipay_pay_method'])
		{
			case '0':
				$service = 'trade_create_by_buyer';
				break;
				
			case '1':
				$service = 'create_direct_pay_by_user';
				break;
				
			case '2':
				$service = 'create_partner_trade_by_buyer';
				break;
		}
		
		$view = new Zend_View();
		self::$_out_trade_no = date('YmdHis').rand(10,99);
		
		$this->_payment = array(
			'extend_param' => 'isv^sh22',
			'service' => $service,                                      /*支付接口名称（不可修改）*/
			'payment_type' => '1',                                      /*支付类型 （1为商品购买）*/
				
			'partner' => $this->_config['alipay_partner'],                               /*商户ID*/
			'seller_email' => $this->_config['alipay_account'],                      /*商户帐号*/
				

			'out_trade_no' => self::$_out_trade_no,
				
			'return_url' => $view->baseUrl().'/order/payment/a/return',   /*同步跳转通知页面*/
			'notify_url' => $view->baseUrl().'/order/payment/a/notity',   /*异步通知页面*/
				
			'sign_type' => 'MD5',                                       /*签名方式*/
			'_input_charset' => 'utf-8',                                /*字符编码*/
				
			'subject'=>'宜活账户充值',                                   /*订单标题*/
			'body' => '您好，宜活有机欢迎您的光临！',
			'quantity' => 1,
			
			/* 物流参数 */
            'logistics_type'    => 'EXPRESS',
            'logistics_payment' => 'BUYER_PAY_AFTER_RECEIVE',
		);
	}
	
	
	public function payment($post)
	{
		$this->_payment['defaultbank'] = $post['defaultbank'];
		$this->_payment['total_fee'] = floatval($post['total_amount']);
		$tnis->_payment['logistics_fee'] = floatval($post['logistics_fee']);
		
		header("Content-type:text/html; charset=utf-8");
		echo $this->_buildForm();
	}
	
	/**
     * 构造提交表单HTML数据
     * @return 提交表单HTML文本
     */
     private function _buildForm()
     {
     	$array_arg = $this->_buildParameter();
     	
     	$payHTMLForm = '<form action="'.$this->_config['alipay_geteway'].'_input_charset='.trim(strtolower($this->_payment['_input_charset'])).'" id="alipay" name="alipay" method="get">';
     	foreach($array_arg as $key => $value) {
     		$payHTMLForm.= '<input type="hidden" name="'.$key.'" value="'.$value.'" />';
     	}
     	$payHTMLForm.= '</form>';
     	
     	$payHTMLForm.= '<script>document.forms["alipay"].submit()</script>';
     	
     	return $payHTMLForm;
     }
     
    /**
     * 生成要请求给支付宝的参数数组
     * @return 要请求的参数数组
     */
    private function _buildParameter()
    {
    	$filter_array = $this->_filter($this->_payment);
    	$sort_array = $this->_sort($filter_array);
    	
    	$sign_str = $this->_buildMySign($sort_array, $this->_config['alipay_key'], strtoupper(trim($this->_payment['sign_type'])));
    	
    	$sort_array['sign'] = $sign_str;
    	$sort_array['sign_type'] = strtoupper(trim($this->_payment['sign_type']));
    	
    	return $sort_array;
    }
	
	
	/**
	 * 对数组排序
	 * @param $array_arg 排序前的数组
	 * return 排序后的数组
	 */
	private function _sort($array_arg)
	{
		ksort($array_arg);
		reset($array_arg);
		return $array_arg;
	}
	
	/**
	 * 除去数组中的空值和签名参数
	 * @param $array_arg 签名参数组
	 * return 去掉空值与签名参数后的新签名参数组
	 */
	private function _filter($array_arg)
	{
		$arg_filter = array();
		foreach($array_arg as $key => $val) {
			if($key == 'sign' || $key == 'sign_type' || $key == '') {
				continue;
			} else {
				$arg_filter[$key] = $array_arg[$key];
			}	
		}
		
		return $arg_filter;
	}
	
	/**
	 * 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
	 * @param $arg_array 需要拼接的数组
	 * return 拼接完成以后的字符串
	 */
	private function _linkString($array_arg)
	{
		$str_arg = '';
		foreach($array_arg as $key => $value) {
			$str_arg.= $key.'='.$value.'&';
		}
		
		$str_arg = substr($str_arg, 0, count($str_arg)-2);
		if(get_magic_quotes_gpc()) 
			$str_arg = stripslashes($str_arg);
			
		return $str_arg;
 	}
 	
 	/**
	 * 生成签名结果
	 * @param $array_arg 要签名的数组
	 * @param $key 支付宝交易安全校验码
	 * @param $sign_type 签名类型 默认值：MD5
	 * return 签名结果字符串
	 */
 	private function _buildMySign($array_arg, $key, $sign_type = "MD5")
 	{
 		$str_arg = $this->_linkString($array_arg);
 		$str_arg = $str_arg.$key;
 		return $this->_sign($str_arg, $sign_type);
 	}
 	
 	/**
	 * 签名字符串
	 * @param $str_arg 需要签名的字符串
	 * @param $sign_type 签名类型 默认值：MD5
	 * return 签名结果
	 */
	private function _sign($str_arg, $sign_type = "MD5")
	{
		if($sign_type == 'MD5') 
		{
			$sign = md5($str_arg);
		}
		elseif($sign_type =='DSA') 
		{
			die("DSA 签名方法待后续开发，请先使用MD5签名方式");
		}
		else 
		{
			die("支付宝暂不支持".$sign_type."类型的签名方式");
		}
		
		return $sign;
	}
	
	public function verifyReturn($getParams)
	{
		if(empty($getParams['out_trade_no']) || empty($getParams['sign']) || empty($getParams['notify_id']))
			return false;
		
		
		$filter_array = $this->_filter($getParams);
		$sort_array = $this->_sort($filter_array);
		
		$mySign = $this->_buildMySign($sort_array, trim($this->_config['alipay_key']), strtoupper(trim($this->_payment['sign_type'])));
		
		$responseText = 'true';
		if(!empty($getParams['notify_id'])) 
		{
			$desturl = $this->_config['alipay_return'].'partner='.$this->_config['alipay_partner'].'&notify_id='.$getParams['notify_id'];
			$responseText = $this->_getHTTPResponse($desturl);
			if (preg_match("/true$/i", $responseText) && $mySign == $getParams["sign"]) 
			{
				if($getParams['trade_status'] == 'TRADE_FINISHED' || $getParams['trade_status'] == 'TRADE_SUCCESS') 
				{
					return true;
				}
				else
				{
					return false;
				}
			} 
			else 
			{
				return false;
			}
		}
	}
	
	/**
	 * 远程获取数据
	 * 注意：该函数的功能可以用curl来实现和代替。curl需自行编写。
	 * $desturl 指定URL完整路径地址
	 * @param $input_charset 编码格式。默认值：utf-8
	 * @param $time_out 超时时间。默认值：60
	 * return 远程输出的数据
	 */
	private function _getHTTPResponse($desturl, $charset = 'utf-8', $timeout = '60')
	{
		$desturl = parse_url($desturl);
		$transports = "ssl://";
		$desturl["port"] = "443";
		$errorno = $errorstr = '';
		$responseText = "";
		
		$fp = fsockopen($transports.$desturl['host'], $desturl['port'], $errorno, $errorstr, $timeout);
		if(!$fp) 
		{
			header("Content-type:text/html; charset=utf-8");
			die("ERROR: $errorno - $errorstr<br />\n");
		}
		else 
		{
			if (trim($charset) == '') 
			{
				fputs($fp, "POST ".$desturl["path"]." HTTP/1.1\r\n");
			}
			else 
			{
				fputs($fp, "POST ".$desturl["path"].'?_input_charset='.$charset." HTTP/1.1\r\n");
			}
			fputs($fp, "Host: ".$desturl["host"]."\r\n");
			fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
			fputs($fp, "Content-length: ".strlen($desturl["query"])."\r\n");
			fputs($fp, "Connection: close\r\n\r\n");
			fputs($fp, $desturl["query"] . "\r\n\r\n");
			while(!feof($fp)) 
			{
				$responseText .= @fgets($fp, 1024);
			}
			
			fclose($fp);
			$responseText = trim(stristr($responseText,"\r\n\r\n"),"\r\n");
			
			return $responseText;
		}
		
	}
	
	public function getTradeNo()
	{
		return self::$_out_trade_no;
	}
	
	/**
	 * 获取核心数据里的配置项
	 * 
	 * @return boolean|multitype:unknown
	 */
	private function _getConfig()
	{
		$db = Zend_Registry::get('db');
		$select = new Zend_Db_Select($db);
		$select->from('st_payment');
		$select->where('pay_code = ?', 'alipay');
		$payment = $db->fetchRow($select);
		if(empty($payment))
			return trigger_error('核心数据丢失，请联系管理员!');
		
		$pay_config = unserialize($payment['pay_config']);
		$config = array();
		
		foreach($pay_config as $row)
			$config[$row['name']] = $row['value'];

		return $config;
	}
}